「数据可视化库王者」D3.js 极速上手到Vue应用

您所在的位置:网站首页 d3 可视化工具 「数据可视化库王者」D3.js 极速上手到Vue应用

「数据可视化库王者」D3.js 极速上手到Vue应用

2024-05-07 02:11| 来源: 网络整理| 查看: 265

前言

D3近年来一直是 JavaScript最重要的数据可视化库之一,在创建者 MikeBostock的维护下,前景依然无量,至少现在没有能打的:

D3与众多其他库的区别在于无限定制的能力(直接操作 SVG)。它的底层 API提供对原生 SVG元素的直接控制,但它也带来了高学习曲线的成本。我们将把 D3和 Vue结合在一起 - 使用 Vue的动态数据绑定,清晰的语法和模块化结构,可以充分发挥 D3的最佳性能。

根据广泛定义,D3可拆分为以下几种分库:

绝大部分的 D3课程或书籍,都会着重讲解在其 DOM操作功能上,但这明显与近几年来的web框架理念相违背。用于数据可视化的 D3,其核心在于使用绘图指令装饰数据,从源数据创建新的可绘制数据,生成 SVG路径以及从数据和方法在 DOM中创建数据可视化元素(如轴)的功能。 有许多用于管理DOM的工具,所有这些工具都可以在 D3中集成数据可视化功能。这也是 D3能与 Vue无缝结合的原因之一。

于此,我们不需要从 D3 DOM操作功能开始学起,直接通过实例来入门 D3。

D3.js 渐进入门

以下实例的模版均为以下形式:

代码语言:javascript复制 Learn D3.js First heading 1. 选择和操作

你需要学习的第一件事是如何使用D3.js选择和操作DOM元素。该库在操作DOM方面实际上非常强大,因此理论上可以将其用作 jQuery的替代品。以下代码请逐行添加运行。

代码语言:javascript复制// index.js d3.select(); d3.selectAll(); d3.select('h1').style('color', 'red') .attr('class', 'heading') .text('Updated h1 tag'); d3.select('body').append('p').text('First Paragraph'); d3.select('body').append('p').text('Second Paragraph'); d3.select('body').append('p').text('Third Paragraph'); d3.selectAll('p').style('')2.数据加载和绑定

当你要创建可视化时,了解如何加载数据以及将其绑定到DOM非常重要。所以在这个实例中,你将学到这两点。

代码语言:javascript复制let dataset = [1, 2, 3, 4, 5]; d3.select('body') .selectAll('p') .data(dataset) .enter() .append('p') // appends paragraph for each data element .text('D3 is awesome!!'); //.text(function(d) { return d; });3.创建一个简单的柱状图

首先需要添加一个 svg标签

代码语言:javascript复制Bar Chart using D3.js

然后在 index.js中添加(已添加关键注释):

代码语言:javascript复制// 数据集 let dataset = [80, 100, 56, 120, 180, 30, 40, 120, 160]; // 定义svg图形宽高,以及柱状图间距 let svgWidth = 500, svgHeight = 300, barPadding = 5; // 通过图形计算每个柱状宽度 let barWidth = (svgWidth / dataset.length); // 绘制图形 let svg = d3.select('svg') .attr("width", svgWidth) .attr("height", svgHeight); // rect,长方形 // 文档:http://www.w3school.com.cn/svg/svg_rect.asp let barChart = svg.selectAll("rect") .data(dataset) //绑定数组 .enter() // 指定选择集的enter部分 .append("rect") // 添加足够数量的矩形 .attr("y", d => svgHeight - d ) // d为数据集每一项的值, 取y坐标 .attr("height", d => d) // 设定高度 .attr("width", barWidth - barPadding) // 设定宽度 .attr("transform", (d, i) => { let translate = [barWidth * i, 0]; return "translate("+ translate +")"; }); // 实际是计算每一项值的x坐标4. 在图形上方显示数值

这时就需要在上述代码中创建 svg的 text文本

代码语言:javascript复制let text = svg.selectAll("text") .data(dataset) .enter() .append("text") .text(d => d) .attr("y", (d, i) => svgHeight - d - 2) .attr("x", (d, i) => barWidth * i) .attr("fill", "#A64C38");

过程比较简单,就是返回文本,计算x/y坐标,并填充颜色。

5. scales: 比例尺函数

D3中有个重要的概念就是比例尺。比例尺就是把一组输入域映射到输出域的函数。映射就是两个数据集之间元素相互对应的关系。比如输入是1,输出是100,输入是5,输出是10000,那么这其中的映射关系就是你所定义的比例尺。

D3中有各种比例尺函数,有连续性的,有非连续性的,在本例子中,你将学到 d3.scaleLinear() ,线性比例尺。

5.1 d3.scaleLinear(),线性比例尺

使用 d3.scaleLinear()创造一个线性比例尺,其中:

domain()是输入域range()是输出域相当于将 domain中的数据集映射到 range的数据集中。代码语言:javascript复制let scale = d3.scaleLinear().domain([1,5]).range([0,100])

映射关系:

值得注意的是,上述代码只是定义了一个映射规则,映射的输入值并不局限于 domain()中的输入域。

代码语言:javascript复制scale(1) // 输出:0 scale(4) // 输出:75 scale(5) // 输出:100 scale(-1) // 输出:-50 scale(10) // 输出:225

于是我们来改造 3~4的例子:

代码语言:javascript复制let dataset = [1,2,3,4,5]; let svgWidth = 500, svgHeight = 300, barPadding = 5; let barWidth = (svgWidth / dataset.length); let svg = d3.select('svg') .attr("width", svgWidth) .attr("height", svgHeight); let yScale = d3.scaleLinear() .domain([0, d3.max(dataset)]) .range([0, svgHeight]); let barChart = svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr("y", d => svgHeight - yScale(d)) .attr("height", d => yScale(d)) .attr("width", barWidth - barPadding) .attr("transform", (d, i) => { let translate = [barWidth * i, 0]; return "translate("+ translate +")"; });

然后就会得到以下图形:

6. Axes:轴

轴是任何图表的组成部分,本例子中将会用到上面讲到的比例尺函数。

代码语言:javascript复制let data= [80, 100, 56, 120, 180, 30, 40, 120, 160]; let svgWidth = 500, svgHeight = 300; let svg = d3.select('svg') .attr("width", svgWidth) .attr("height", svgHeight); // 首先是拿最大值构建x轴坐标 let xScale = d3.scaleLinear() .domain([0, d3.max(data)]) .range([0, svgWidth]); // 接下来是反转值,用作y轴坐标。 let yScale = d3.scaleLinear() .domain([0, d3.max(data)]) .range([svgHeight, 0]); // 横轴的API使用 let x_axis = d3.axisBottom() .scale(xScale); // 纵轴的API使用 let y_axis = d3.axisLeft() .scale(yScale); // 在svg中提供了如g元素这样的将多个元素组织在一起的元素。 // 由g元素编组在一起的可以设置相同的颜色,可以进行坐标变换等,类似于Vue中的 svg.append("g") .attr("transform", "translate(50, 10)") .call(y_axis); let xAxisTranslate = svgHeight - 20; svg.append("g") .attr("transform", "translate(50, " + xAxisTranslate +")") .call(x_axis);7. 创建简易的 SVG元素

在这里面,你会创建 , 和 元素

代码语言:javascript复制let svgWidth = 600, svgHeight = 500; let svg = d3.select("svg") .attr("width", svgWidth) .attr("height", svgHeight) .attr("class", "svg-container") let line = svg.append("line") .attr("x1", 100) .attr("x2", 500) .attr("y1", 50) .attr("y2", 50) .attr("stroke", "red"); let rect = svg.append("rect") .attr("x", 100) .attr("y", 100) .attr("width", 200) .attr("height", 100) .attr("fill", "#9B95FF"); let circle = svg.append("circle") .attr("cx", 200) .attr("cy", 300) .attr("r", 80) .attr("fill", "#7CE8D5");8. 创建饼图代码语言:javascript复制let data = [ {"platform": "Android", "percentage": 40.11}, {"platform": "Windows", "percentage": 36.69}, {"platform": "iOS", "percentage": 13.06} ]; let svgWidth = 500, svgHeight = 300, radius = Math.min(svgWidth, svgHeight) / 2; let svg = d3.select('svg') .attr("width", svgWidth) .attr("height", svgHeight); //Create group element to hold pie chart let g = svg.append("g") .attr("transform", "translate(" + radius + "," + radius + ")") ; // d3.scaleOrdinal() 序数比例尺 // schemeCategory10, 颜色比例尺 // D3提供了一些颜色比例尺,10就是10种颜色,20就是20种: let color = d3.scaleOrdinal(d3.schemeCategory10); let pie = d3.pie().value(d => d.percentage); let path = d3.arc() .outerRadius(radius) .innerRadius(0); let arc = g.selectAll("arc") .data(pie(data)) .enter() .append("g"); arc.append("path") .attr("d", path) .attr("fill", d => color(d.data.percentage)); let label = d3.arc() .outerRadius(radius) .innerRadius(0); arc.append("text") .attr("transform", d => `translate(${label.centroid(d)})`) .attr("text-anchor", "middle") .text(d => `${d.data.platform}:${d.data.percentage}%`);9. 创建折线图

最后,你将学习如何创建折线图以显示近四个月的比特币价格。要获取数据,你将使用外部API。这个项目还将你在整个课程中学到的很多概念结合在一起,所以这是一个很好的可视化课程结束。

代码语言:javascript复制// 外部API,注意日期记得补零 const api = 'https://api.coindesk.com/v1/bpi/historical/close.json?start=2019-03-31&end=2019-07-01'; /** * dom内容加载完毕时,从API中加载数据 */ document.addEventListener("DOMContentLoaded", function(event) { fetch(api) .then(response => response.json()) .then(data => { let parsedData = parseData(data); drawChart(parsedData); }) .catch(err => console.log(err)) }); /** * 将数据解析为键值对 */ parseData = data =>{ let arr = []; for (let i in data.bpi) { arr.push({ date: new Date(i), //date value: +data.bpi[i] //convert string to number }); } return arr; } /** * 创建图表 */ drawChart = data => { let svgWidth = 600, svgHeight = 400; let margin = { top: 20, right: 20, bottom: 30, left: 50 }; let width = svgWidth - margin.left - margin.right; let height = svgHeight - margin.top - margin.bottom; let svg = d3.select('svg') .attr("width", svgWidth) .attr("height", svgHeight); let g = svg.append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); let x = d3.scaleTime() .rangeRound([0, width]); let y = d3.scaleLinear() .rangeRound([height, 0]); let line = d3.line() .x(d=> x(d.date)) .y(d=> y(d.value)) x.domain(d3.extent(data, function(d) { return d.date })); y.domain(d3.extent(data, function(d) { return d.value })); g.append("g") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)) .select(".domain") .remove(); g.append("g") .call(d3.axisLeft(y)) .append("text") .attr("fill", "#000") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", "0.71em") .attr("text-anchor", "end") .text("Price ($)"); g.append("path") .datum(data) .attr("fill", "none") .attr("stroke", "steelblue") .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round") .attr("stroke-width", 1.5) .attr("d", line); }

以上原实例均来自:Learn D3 for free。scrimba是一个非常神奇的网站。它是使用交互式编码截屏工具构建的。

所有的操作都是:

暂停截屏视频 → 编辑代码 → 运行它!→ 查看更改

非常值得安利一波。接下来进入第二部分: Vue中使用 D3.js的正确姿势

2. Vue中使用 D3.js的正确姿势

我们将使用 D3和 Vue构建一个基本的柱状图组件。网上有一堆例子,但我们将专注于写 Vue,而不是滥用D3。

1. 安装依赖

首先,我们需要为项目安装依赖项。我们可以简单地安装和使用 D3整库:

代码语言:javascript复制npm i d3

但我在前面讲到,实际上 D3是几个分库的集合,考虑到项目的优化,我们只安装所需的模块。

使用 VueCli 初始化项目即可。

2. 创建柱状图3. 柱状图模块导入4. 创建 svg元素

因 Vue数据响应的特性,我们不需要用到 D3操作 DOM的那套链式创建。

5. 数据与窗口大小响应

在 mounted钩子中,我们将为窗口调整大小事件添加一个监听器,它将触发绘制动画,并将 大小设置为新窗口的比例。我们不会立即渲染,而是等待 300毫秒,以确保完全调整窗口大小。

以下是完整的 BarChart.vue,请配合注释食用:

代码语言:javascript复制 {{ title }} import { scaleLinear, scaleBand } from "d3-scale"; import { max, min } from "d3-array"; import { selectAll } from "d3-selection"; import { transition } from "d3-transition"; export default { name: "BarChart", props: { title: String, xKey: String, yKey: String, data: Array }, mounted() { this.svgWidth = document.getElementById("container").offsetWidth * 0.75; this.AddResizeListener(); this.AnimateLoad(); }, data: () => ({ svgWidth: 0, redrawToggle: true }), methods: { // 绘制柱形 AnimateLoad() { selectAll("rect") .data(this.data) .transition() .delay((d, i) => { return i * 150; }) .duration(1000) .attr("y", d => { return this.yScale(d[this.yKey]); }) .attr("height", d => { return this.svgHeight - this.yScale(d[this.yKey]); }); }, // 调整窗口大小后300毫秒重新绘制图表 // 即响应式绘制 AddResizeListener() { window.addEventListener("resize", () => { this.$data.redrawToggle = false; setTimeout(() => { this.$data.redrawToggle = true; this.$data.svgWidth = document.getElementById("container").offsetWidth * 0.75; this.AnimateLoad(); }, 300); }); } }, computed: { dataMax() { return max(this.data, d => { return d[this.yKey]; }); }, dataMin() { return min(this.data, d => { return d[this.yKey]; }); }, xScale() { return scaleBand() .rangeRound([0, this.svgWidth]) .padding(0.1) .domain( this.data.map(d => { return d[this.xKey]; }) ); }, // 通过线性比例尺自动生成 yScale() { return scaleLinear() .rangeRound([this.svgHeight, 0]) .domain([this.dataMin > 0 ? 0 : this.dataMin, this.dataMax]); }, svgHeight() { return this.svgWidth / 1.61803398875; // 黄金比例 } } }; .bar-positive { fill: steelblue; transition: r 0.2s ease-in-out; } .bar-positive:hover { fill: brown; } .svg-container { display: inline-block; position: relative; width: 100%; padding-bottom: 1%; vertical-align: top; overflow: hidden; }

我们将从父组件 App.vue获取数据:

代码语言:javascript复制 import BarChart from "./components/BarChart.vue"; export default { name: "App", components: { BarChart }, data: () => ({ barChartData: [ { name: "张三", amount: 25 }, { name: "李四", amount: 40 }, { name: "老王", amount: 15 }, { name: "老赖", amount: 9 } ] }) }; #app { font-family: "Open Sans", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #282f36; margin-top: 30px; }

这时候 yarn run serve后将会看到:

好像还缺点显示数值,考虑到该图高度是根据比例尺生成,我们调整下y坐标:

代码语言:javascript复制yScale() { return scaleLinear() .rangeRound([this.svgHeight, 0]) .domain([this.dataMin > 0 ? 0 : this.dataMin + 2, this.dataMax + 2]); },

在 AnimateLoad()末尾添加:

代码语言:javascript复制selectAll("text") .data(this.data) .enter()

最后在 元素中添加:

代码语言:javascript复制{{ item[xKey]}} {{ item[yKey]}} 3. 参考文章D3 is not a Data Visualization Library D3中常用的比例尺D3 vs G2 vs Echarts Dynamic Data Visualizations With Vue.js and D3 4. 总结

该库几乎凭 MikeBostock 一人之力完成,且在学术界、专业团队中享有极大声誉。

D3更接近底层,与 g2、 echarts 不同, d3 能直接操作 svg,所以拥有极大的自由度,几乎可以实现任何 2d 的设计需求。正如其名 DataDrivenDocuments,其本质是将数据与 DOM 绑定,并将数据映射至 DOM 属性上。D3 长于可视化,而不止于可视化,还提供了 数据处理、 数据分析、 DOM 操作等诸多功能。如果有想深耕数据可视化方面的前端, D3不得不学。

掌握 D3 后,限制作品水平的只会是想象力而不再是技术。

源码地址:点这里

作者掘金文章总集

需要转载到公众号的喊我加下白名单就行了。

「真®全栈之路」Web前端开发的后端指南「Vue实践」5分钟撸一个Vue CLI 插件「Vue实践」武装你的前端项目「中高级前端面试」JavaScript手写代码无敌秘籍「从源码中学习」面试官都不知道的Vue题目答案「从源码中学习」Vue源码中的JS骚操作「从源码中学习」彻底理解Vue选项Props「Vue实践」项目升级vue-cli3的正确姿势为何你始终理解不了JavaScript作用域链?


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3